package org.grow.loginto.controller;

import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.QueryResults;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.grow.loginto.dao.LeaveEntityDao;
import org.grow.loginto.entity.*;
import org.grow.loginto.entity.QLeaveEntity;
import org.grow.loginto.entity.enums.ApplyState;
import org.grow.loginto.entity.enums.AuditState;
import org.grow.loginto.exception.JulyException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * @Author: xwg
 * @CreateDate: 21-6-8
 */
@RestController
@RequestMapping("/leaveAbout")
public class LeaveController {
    @Autowired
    private LeaveEntityDao leaveEntityDao;

    //    新建一次请假
    @PostMapping("/leave")
    public Boolean insert(@RequestBody LeaveEntity leaveEntity) {
        System.out.println("got " + leaveEntity);
        UserInfo principal = (UserInfo) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        leaveEntity.setLeaveId(0);
        leaveEntity.setApplier(principal.getUsername());
        leaveEntity.setAuditor(null);
        leaveEntity.setAuditorWord(null);
        leaveEntity.setApplyTime(LocalDateTime.now());
        leaveEntity.setApplyState(ApplyState.saved);
        leaveEntity.setAuditState(AuditState.notAudit);
        System.out.println(" final " + leaveEntity);
        leaveEntityDao.save(leaveEntity);
        return true;
    }

    //    申请人查询一条详细信息
    @GetMapping("/leave/apply/{leaveId}")
    public LeaveEntity applyFindOne(@PathVariable("leaveId") Integer leaveId) {

        UserInfo principal = (UserInfo) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        LeaveEntity leaveEntity = leaveEntityDao.findByLeaveIdAndApplier(leaveId, principal.getUsername());
        if (leaveEntity == null) throw new JulyException("此条目可能不是该用户的");
        return leaveEntity;


    }
    //    审核人查询一条详细信息
    @GetMapping("/leave/audit/{leaveId}")
    public LeaveEntity auditFindOne(@PathVariable("leaveId") Integer leaveId) {

//        UserInfo principal = (UserInfo) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        LeaveEntity leaveEntity = leaveEntityDao.findByLeaveIdAndApplyState(leaveId,ApplyState.submitted);
        if (leaveEntity == null) throw new JulyException("此条目可能不是需要审核的");
        return leaveEntity;


    }

    @PutMapping("/leave/modify")
    public Boolean modify(@RequestBody LeaveEntity leaveEntity) {
        if (leaveEntity.getApplyState() != ApplyState.saved)
            throw new JulyException("只有未提交的请假单才可以修改");
        if (leaveEntity.getAuditState() != AuditState.notAudit)
            throw new JulyException("只有在审核之前才可以修改");
        boolean present = leaveEntityDao.findById(leaveEntity.getLeaveId()).isPresent();
        if (!present)
            throw new JulyException("不明原因，数据库无此请假单,不能修改");
        leaveEntity.setApplyTime(LocalDateTime.now());
        leaveEntityDao.save(leaveEntity);
        return true;

    }

    //    点击提交按钮 主要是写上申请时间
    @PutMapping("/leave/submit/{leaveId}")
    public Boolean submit(@PathVariable("leaveId") Integer leaveId) {
        Optional<LeaveEntity> leaveEntity = leaveEntityDao.findById(leaveId);
        if (!leaveEntity.isPresent()) {
            throw new JulyException("提交请假条不存在");
        }

        LeaveEntity leave = leaveEntity.get();
        if (leave.getApplyState() != ApplyState.saved) {
            throw new JulyException("请假条不是暂存状态不能提交");
        }
        leave.setApplyState(ApplyState.submitted);
        leave.setApplyTime(LocalDateTime.now());
        leaveEntityDao.save(leave);
        return true;
    }

    @Autowired
    private JPAQueryFactory jpaQueryFactory;
    QLeaveEntity l = QLeaveEntity.leaveEntity;

    @PostMapping("/leave/query/apply")
    public LeavePageResults applyQuery(@RequestBody ApplyLeavePageQuery leavePageQuery) {
        System.out.println(leavePageQuery);
        UserInfo principal = (UserInfo) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        ApplyLeaveQueryCondition qc = leavePageQuery.getQueryCondition();
        Integer pageNum = leavePageQuery.getPageNum();
        Integer pageSize = leavePageQuery.getPageSize();
        Integer pageStart = (pageNum - 1) * pageSize;
        System.out.println(pageNum + "   --- " + pageSize + " ===> " + principal.getUsername());
        BooleanBuilder builder = new BooleanBuilder();
//        动态
        if (StringUtils.hasText(qc.getAuditorSimilar())) {

            builder.and(l.auditor.like(qc.getAuditorSimilar()));
        }
        if (qc.getLeaveTypes() != null && !qc.getLeaveTypes().isEmpty()) {

            builder.and(l.leaveType.in(qc.getLeaveTypes()));
        }
        if (qc.getApplyStates() != null && !qc.getApplyStates().isEmpty()) {

            builder.and(l.applyState.in(qc.getApplyStates()));
        }
        if (qc.getLeaveId() != null && qc.getLeaveId() > 0) {

            builder.and(l.leaveId.eq(qc.getLeaveId()));
        }
        if (qc.getApplyTimeStart() != null) {

            builder.and(l.applyTime.after(qc.getApplyTimeStart()));
        }
        if (qc.getApplyTimeEnd() != null) {

            builder.and(l.applyTime.before(qc.getApplyTimeEnd()));
        }
//        静态

        builder.and(l.applier.eq(principal.getUsername()));
//        builder.and()

        QueryResults<LeaveEntity> fetchResults = jpaQueryFactory.selectFrom(l)
//        QueryResults<ApplySelectedDto> fetchResults = jpaQueryFactory.select(
//                Projections.bean(ApplySelectedDto.class)).from(l)
                .where(builder)
                .orderBy(l.leaveId.desc())
                .offset(pageStart)
                .limit(pageSize)
                .fetchResults();
        LeavePageResults<LeaveEntity> pageResults = new LeavePageResults<>();
//        LeavePageResults<ApplySelectedDto> pageResults = new LeavePageResults<>();
        pageResults.setResults(fetchResults.getResults());
        pageResults.setTotal(fetchResults.getTotal());
        return pageResults;

    }

    @PostMapping("/leave/query/audit")
    public LeavePageResults<AuditSelectedDto> auditQuery(@RequestBody AuditLeavePageQuery leavePageQuery) {

        AuditLeaveQueryCondition qc = leavePageQuery.getQueryCondition();
        Integer pageNum = leavePageQuery.getPageNum();
        Integer pageSize = leavePageQuery.getPageSize();
        Integer pageStart = (pageNum - 1) * pageSize;

        BooleanBuilder builder = new BooleanBuilder();
    /*    private String applierSimilar;
    private List<LeaveType> leaveTypes;
    private Integer leaveId;
    private List<AuditState> auditStates;
    private LocalDateTime applyTimeStart;
    private LocalDateTime applyTimeEnd;*/
        if (StringUtils.hasText(qc.getApplierSimilar())){

            builder.and(l.applier.like(qc.getApplierSimilar()));
        }
        if (!CollectionUtils.isEmpty(qc.getLeaveTypes())){

            builder.and(l.leaveType.in(qc.getLeaveTypes()));
        }
        if (qc.getLeaveId()!=null && qc.getLeaveId()>0){

            builder.and(l.leaveId.eq(qc.getLeaveId()));
        }
        if (!CollectionUtils.isEmpty(qc.getAuditStates())){

            builder.and(l.auditState.in(qc.getAuditStates()));
        }
        if (qc.getApplyTimeEnd()!=null){

            builder.and(l.applyTime.before(qc.getApplyTimeEnd()));
        }
        if (qc.getApplyTimeStart()!=null){

            builder.and(l.applyTime.after(qc.getApplyTimeStart()));
        }


        builder.and(l.applyState.in(ApplyState.submitted));
    /*    private Integer leaveId;
    private String applier;
    private String auditor;
    private LeaveType leaveType;

    private ApplyState applyState;

    private AuditState auditState;
    private LocalDateTime applyTime;*/

        QueryResults<AuditSelectedDto> fetchResults = jpaQueryFactory.select(
                Projections.bean(AuditSelectedDto.class,
                        l.leaveId,
                        l.applier,
                        l.auditor,
                        l.leaveType,
                        l.applyState,
                        l.auditState,
                        l.applyTime)
        )
                .from(l)
                .where(builder)
                .orderBy(l.leaveId.desc())
                .offset(pageStart)
                .limit(pageSize)
                .fetchResults();


        LeavePageResults<AuditSelectedDto> pageResults = new LeavePageResults<>();
        pageResults.setResults(fetchResults.getResults());
        pageResults.setTotal(fetchResults.getTotal());
        return pageResults;
    }
    @PutMapping("/leave/audit/succeed")
    public Boolean auditSucceed(@RequestBody LeaveEntity leaveEntity){
        UserInfo principal = (UserInfo) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (leaveEntity.getAuditState()!=AuditState.notAudit) throw new JulyException("只有未审核状态的才能审核");
        leaveEntity.setAuditor(principal.getUsername());
        leaveEntity.setAuditState(AuditState.auditSucceed);
        leaveEntityDao.save(leaveEntity);
        return true;
    }
    @PutMapping("/leave/audit/failed")
    public Boolean auditFailed(@RequestBody LeaveEntity leaveEntity){
        UserInfo principal = (UserInfo) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (leaveEntity.getAuditState()!=AuditState.notAudit) throw new JulyException("只有未审核状态的才能审核");
        leaveEntity.setAuditor(principal.getUsername());
        leaveEntity.setAuditState(AuditState.auditFailed);
        leaveEntityDao.save(leaveEntity);
        return true;
    }
    @PutMapping("/leave/confirm/{leaveId}")
    public Boolean confirm(@PathVariable("leaveId") Integer leaveId){
        Optional<LeaveEntity> leaveEntity = leaveEntityDao.findById(leaveId);
        if (!leaveEntity.isPresent()) {
            throw new JulyException("待确认的请假条不存在");
        }

        LeaveEntity leave = leaveEntity.get();
        AuditState auditState = leave.getAuditState();

        Boolean allow = false;
        if (auditState == AuditState.auditSucceed) allow =true;
        if (auditState == AuditState.auditFailed) allow = true;

        if (leave.getApplyState()!= ApplyState.submitted) {
            throw new JulyException("请假条只有在已提交才能确认");
        }
        if(!allow)
            throw new JulyException("请假条只有在审核完毕才能确认");
        leave.setApplyState(ApplyState.ended);
        leave.setApplyTime(LocalDateTime.now());
        leaveEntityDao.save(leave);
        return true;
    }
}
